#include "vtkFieldExport_SWEBoundary.hpp"

#include "bc_swe_all.hpp"

namespace hms::vtk
{

template<typename MeshType>
void writeBoundaryCondition(
	xml::XMLElement* bcElem,
	const FreeOutflow_waterdepth<MeshType>* bc
){
	bool isLimited { bc->isLimited() };
	bcElem->SetAttribute( "isLimited", isLimited );
	if (isLimited)
		bcElem->SetAttribute( "limit", bc->limit() );
}

template<typename MeshType>
void writeSWEBoundaryCondition(
	xml::XMLElement* bcElem,
	const BoundaryCondition<MeshType>* bc
){
	using T = boundaryCondition::Type;

	auto writeOrthFlow = [&]( const auto* ptr ){
		bcElem->SetAttribute( "OrthogonalVelocity", ptr->vBoundary() );
	};
	auto writeSlope = [&]( const auto* ptr ){
		bcElem->SetAttribute( "angle", ptr->alpha() );
		bcElem->SetAttribute( "isRadians", true );
	};

	/* reduce repetition of template parameter, const and syntax */
	#define CAST_TO(TYPE) \
	dynamic_cast<const TYPE<MeshType>*>(bc)

	switch( bc->type() ){
		case T::orthogonalDischarge_waterdepth: break;
		case T::freeOutflow_velocity: break;
		case T::slip_velocity: break;
		case T::constantWaterDepth_velocity:
			bcElem->SetAttribute(
				"WaterDepth",
				CAST_TO(ConstantWaterDepth_velocity)->dGhost()
			);
			break;
		case T::freeOutflow_waterdepth:
			writeBoundaryCondition(
				bcElem,
				CAST_TO(FreeOutflow_waterdepth)
			);
			break;
		case T::orthogonalDischarge_velocity:
			bcElem->SetAttribute(
				"discharge",
				CAST_TO(OrthogonalDischarge_velocity)->qBoundary()
			);
			break;
		case T::orthogonalFlowVelocity_velocity:
			writeOrthFlow( CAST_TO(OrthogonalFlowVelocity_velocity) );
			break;
		case T::orthogonalFlowVelocity_waterdepth:
			writeOrthFlow( CAST_TO(OrthogonalFlowVelocity_waterdepth) );
			break;
		case T::weir_velocity:   [[fallthrough]];
		case T::weir_waterdepth: [[fallthrough]];
		case T::weir_bottomElevation:
			writeSlope( CAST_TO(Weir_base) );
			break;
		default:
			assert(false);
			throw BoundaryConditionError( fmt::format(
				"Export of type {} not implemented!",
				bold( magic_enum::enum_name( bc->type() ) )
			) );
	}
	#undef CAST_TO
}

#define INSTANTIATE_FOR_ALL_MESHTYPES(MeshType) \
template void writeSWEBoundaryCondition( \
	xml::XMLElement*, const BoundaryCondition<MeshType>* );
#include "meshInstantiator.hpp"

} // end namespace hms
